﻿/*******************************************************
* Copyright (c) 2018-2088, By XuXiang all rights reserved.
*
* FileName: MatchModule.cpp
* Summary: 匹配模块。
*
* Author: XuXiang
* Date: 2024-04-24 21:51
*******************************************************/

#include "MatchModule.h"
#include "../Login/LoginDefine.h"
#include "../Login/LoginModule.h"
#include "../Fight/FightDefine.h"
#include "../Fight/FightModule.h"
#include "MatchDefine.h"
#include "../../Game/ServerGame.h"
#include <algorithm>
#include <sstream>
#include <Frame/MainBase.h>
#include <Frame/ServerBase.h>
#include <Frame/NetManagerBase.h>
#include <Frame/EventManager.h>
#include <Protocol/NetMsgMatch.h>
#include <Util/StringUtil.h>
#include <Util/TimeUtil.h>

namespace Competition
{
	const int MatchModule::MATCH_GROUP_NUMBER = 2;

	const int MatchModule::PREPARE_WAIT_TIME = 10;

	MatchModule::MatchModule() : m_BroadcastCount(0), m_CurGroupID(0)
	{
	}

	MatchModule::~MatchModule()
	{
		SAFE_DELETE_MAP(m_FreeUsers);
		SAFE_DELETE_VECTOR(m_WaitMatchInfos);
		SAFE_DELETE_MAP(m_PrepareGroups);
		SAFE_DELETE_MAP(m_CompleteUsers);
	}

	void MatchModule::RegisterNetMessage(NetManagerBase *pMgr)
	{
		NET_REGISTER(pMgr, MsgID::CS_PLAYER_NUMBER, OnPlayerNumberRequest);
		NET_REGISTER(pMgr, MsgID::CS_MATCH_BEGIN, OnMatchBeginRequest);
		NET_REGISTER(pMgr, MsgID::CS_MATCH_CANCEL, OnMatchCancelRequest);
		NET_REGISTER(pMgr, MsgID::CS_MATCH_CONFIRM, OnMatchConfirmRequest);

		EventManager* emgr = EventManager::GetInstance();
		emgr->RegisterCallBack(LoginEvent::EID_USER_ONLINE, OnEventUserOnline, this);
		emgr->RegisterCallBack(LoginEvent::EID_USER_OUTLINE, OnEventUserOutline, this);
		emgr->RegisterCallBack(LoginEvent::EID_USER_QUIT, OnEventUserQuit, this);
		emgr->RegisterCallBack(FightEvent::EID_FIGHT_IN, OnEventFightIn, this);
		emgr->RegisterCallBack(FightEvent::EID_FIGHT_OUT, OnEventFightOut, this);
	}

	void MatchModule::RegisterStorageMessage(StorageManager* pMgr)
	{

	}

	void MatchModule::AddConfig(vector<ModuleConfig*> &cfgs)
	{
	}

	void MatchModule::Init()
	{
		ModuleBase::Init();
		m_CurGroupID = 1;
	}

	void MatchModule::Release()
	{
		ModuleBase::Release();
	}

	void MatchModule::OnUpdatePerSecond()
	{
		if (m_BroadcastCount > 0)
		{
			if (--m_BroadcastCount == 0)
			{
				BroadcastPlayerNumber();
			}
		}
		CheckPrepareTime();
	}

	void MatchModule::BroadcastPlayerNumber()
	{
		SCPlayerNumberResponse res;
		res.LobbyNumber = (int)(m_FreeUsers.size() + m_WaitMatchInfos.size() + m_PrepareGroups.size() * MATCH_GROUP_NUMBER);
		res.FightNumber = (int)m_CompleteUsers.size();
		::printf("MatchModule::BroadcastPlayerNumber Lobby:%d Fight:%d\n", res.LobbyNumber, res.FightNumber);

		for (MatchInfoMap::iterator itr = m_FreeUsers.begin(); itr != m_FreeUsers.end(); ++itr)
		{
			SendNet(itr->second->GetUserID(), MsgID::SC_PLAYER_NUMBER, &res);
		}
		for (MatchInfoVector::iterator itr = m_WaitMatchInfos.begin(); itr != m_WaitMatchInfos.end(); ++itr)
		{
			SendNet((*itr)->GetUserID(), MsgID::SC_PLAYER_NUMBER, &res);
		}
		for (std::map<int, int>::iterator itr = m_UserToGroup.begin(); itr != m_UserToGroup.end(); ++itr)
		{
			SendNet(itr->first, MsgID::SC_PLAYER_NUMBER, &res);
		}
	}

	void MatchModule::CheckPrepareTime()
	{
		//找出超时的组
		Int64 now = TimeUtil::GetCurrentSecond();
		vector<int> need_remove;
		for (MatchGroupMap::iterator itr = m_PrepareGroups.begin(); itr != m_PrepareGroups.end(); ++itr)
		{
			int gap = (int)(now - itr->second->GetStartTime());
			if (gap > PREPARE_WAIT_TIME)
			{
				need_remove.push_back(itr->first);
			}
		}

		//移除掉，并通知超时
		for (vector<int>::iterator itr = need_remove.begin(); itr != need_remove.end(); ++itr)
		{
			MatchGroupMap::iterator itr2 = m_PrepareGroups.find(*itr);
			MatchGroupInfo* group = itr2->second;
			MatchInfoVector& infos = group->GetMatchInfos();
			itr2 = m_PrepareGroups.erase(itr2);

			//清空列表，再删除匹配组
			SCMatchResultNotify ntf;
			ntf.Result = 3;
			for (MatchInfoVector::iterator itr3 = infos.begin(); itr3 != infos.end();)
			{
				MatchInfo* info = *itr3;
				info->SetState(0);
				itr3 = infos.erase(itr3);

				//移动到未匹配列表并通知
				m_UserToGroup.erase(info->GetUserID());
				m_FreeUsers.insert(MatchInfoMap::value_type(info->GetUserID(), info));
				SendNet(info->GetUserID(), MsgID::SC_MATCH_RESULT, &ntf);
			}
			SAFE_DELETE(group);
		}
	}

	void MatchModule::RemovePlayer(int user_id)
	{
		//自由用户判断
		MatchInfoMap::iterator itr = m_FreeUsers.find(user_id);
		if (itr != m_FreeUsers.end())
		{
			MatchInfo* info = itr->second;
			itr = m_FreeUsers.erase(itr);
			SAFE_DELETE(info);
			return;
		}

		//等待匹配用户判断
		for (MatchInfoVector::iterator itr2 = m_WaitMatchInfos.begin(); itr2 != m_WaitMatchInfos.end(); ++itr2)
		{
			MatchInfo* info = *itr2;
			if (info->GetUserID() == user_id)
			{
				m_WaitMatchInfos.erase(itr2);
				SAFE_DELETE(info);
				return;
			}
		}

		//准备中的用户判断
		std::map<int, int>::iterator itr3 = m_UserToGroup.find(user_id);
		if (itr3 != m_UserToGroup.end())
		{
			MatchGroupMap::iterator itr3_1 = m_PrepareGroups.find(itr3->second);
			if (itr3_1 != m_PrepareGroups.end())
			{
				MatchGroupInfo* group = itr3_1->second;
				MatchInfoVector& infos = group->GetMatchInfos();
				itr3_1 = m_PrepareGroups.erase(itr3_1);

				//清空列表，再删除匹配组
				SCMatchResultNotify ntf;
				ntf.Result = 2;			//掉线按取消处理
				for (MatchInfoVector::iterator itr3_2 = infos.begin(); itr3_2 != infos.end();)
				{
					MatchInfo* info = *itr3_2;
					itr3_2 = infos.erase(itr3_2);
					m_UserToGroup.erase(info->GetUserID());
					if (info->GetUserID() == user_id)
					{
						SAFE_DELETE(info);
					}
					else
					{
						//移动到未匹配列表并通知
						info->SetState(0);
						m_FreeUsers.insert(MatchInfoMap::value_type(info->GetUserID(), info));
						SendNet(info->GetUserID(), MsgID::SC_MATCH_RESULT, &ntf);
					}
				}
				SAFE_DELETE(group);
				return;
			}
		}

		//匹配完成用户判断
		MatchInfoMap::iterator itr4 = m_CompleteUsers.find(user_id);
		if (itr4 != m_CompleteUsers.end())
		{
			MatchInfo* info = itr4->second;
			itr4 = m_CompleteUsers.erase(itr4);
			SAFE_DELETE(info);
			m_UserToGroup.erase(user_id);
			return;
		}
	}

	void MatchModule::OnPlayerNumberRequest(NetDataItem* item)
	{
		CSPlayerNumberRequest req;
		req.Unpack(item->data, 0);
		::printf("MatchModule::OnPlayerNumberRequest\n");

		SCPlayerNumberResponse res;
		res.LobbyNumber = (int)(m_FreeUsers.size() + m_WaitMatchInfos.size() + m_PrepareGroups.size() * 2);
		res.FightNumber = (int)m_CompleteUsers.size();
		MainBase::GetCurMain()->GetNetManager()->Send(item->uid, MsgID::SC_PLAYER_NUMBER, &res);
	}

	void MatchModule::OnMatchBeginRequest(NetDataItem* item)
	{
		int user_id = (int)item->key.second;
		::printf("MatchModule::OnMatchBeginRequest user_id:%d\n", user_id);
		MatchInfoMap::iterator itr = m_FreeUsers.find(user_id);
		if (itr == m_FreeUsers.end())
		{
			::printf("Player is not in free.\n");
			return;
		}

		SCMatchBeginResponse res;
		FightModule* fight_module = GetServer()->GetModule<FightModule>();
		int state = fight_module->GetPlayerFightState(user_id);
		res.Result = state == FightPlayerState::FPS_NONE ? 0 : 1;
		SendNet(user_id, MsgID::SC_MATCH_BEGIN, &res);
		if (state != FightPlayerState::FPS_NONE)
		{
			::printf("Player fight state is %d.\n", state);
			return;
		}

		//判断匹配人数是否足够
		m_WaitMatchInfos.push_back(itr->second);
		itr = m_FreeUsers.erase(itr);
		if (m_WaitMatchInfos.size() < MATCH_GROUP_NUMBER)
		{
			::printf("Wait other player, The wait list size is %d now.\n", (int)m_WaitMatchInfos.size());
			return;
		}

		//创建匹配组
		MatchGroupInfo* group = new MatchGroupInfo(m_CurGroupID++);
		group->SetStartTime(TimeUtil::GetCurrentSecond());
		for (int i = 0; i < MATCH_GROUP_NUMBER; ++i)
		{
			MatchInfo *info = m_WaitMatchInfos[i];
			group->AddMatchInfo(info);
			info->SetState(0);
			m_UserToGroup.insert(std::map<int, int>::value_type(info->GetUserID(), group->GetGroupID()));
		}
		m_WaitMatchInfos.erase(m_WaitMatchInfos.begin(), m_WaitMatchInfos.begin() + MATCH_GROUP_NUMBER);
		m_PrepareGroups.insert(MatchGroupMap::value_type(group->GetGroupID(), group));
		::printf("Match success! The match goup id is %d.\n", group->GetGroupID());

		//通知玩家匹配成功
		LoginModule* login_module = GetServer()->GetModule<LoginModule>();
		SCMatchSuccessNotify ntf;
		ntf.PlayerCount = MATCH_GROUP_NUMBER;
		for (int i = 0; i < MATCH_GROUP_NUMBER; ++i)
		{
			MatchInfo *info = group->GetMatchInfos()[i];
			MatchPlayerInfo pinfo;
			pinfo.UserID = info->GetUserID();
			pinfo.NickName = login_module->GetUser(info->GetUserID())->GetNickName();
			ntf.PlayerList.push_back(pinfo);
		}
		ntf.StartTime = TimeUtil::GetCurrentMillisecond();
		ntf.WaitTime = PREPARE_WAIT_TIME;
		for (int i = 0; i < MATCH_GROUP_NUMBER; ++i)
		{
			MatchInfo* info = group->GetMatchInfos()[i];
			SendNet(info->GetUserID(), MsgID::SC_MATCH_SUCCESS, &ntf);
		}
	}

	void MatchModule::OnMatchCancelRequest(NetDataItem* item)
	{
		//等待匹配用户取消
		int user_id = (int)item->key.second;
		::printf("MatchModule::OnMatchCancelRequest user_id:%d\n", user_id);
		for (MatchInfoVector::iterator itr2 = m_WaitMatchInfos.begin(); itr2 != m_WaitMatchInfos.end(); ++itr2)
		{
			MatchInfo* info = *itr2;
			if (info->GetUserID() == user_id)
			{
				m_WaitMatchInfos.erase(itr2);
				m_FreeUsers.insert(MatchInfoMap::value_type(info->GetUserID(), info));
				SCMatchResultNotify ntf;
				ntf.Result = 1;
				SendNet(info->GetUserID(), MsgID::SC_MATCH_RESULT, &ntf);
				return;
			}
		}

		//准备中的用户取消
		std::map<int, int>::iterator itr = m_UserToGroup.find(user_id);
		if (itr != m_UserToGroup.end())
		{
			MatchGroupMap::iterator itr2 = m_PrepareGroups.find(itr->second);
			if (itr2 != m_PrepareGroups.end())
			{
				MatchGroupInfo* group = itr2->second;
				MatchInfoVector& infos = group->GetMatchInfos();
				itr2 = m_PrepareGroups.erase(itr2);

				//清空列表，再删除匹配组
				for (MatchInfoVector::iterator itr3 = infos.begin(); itr3 != infos.end();)
				{
					MatchInfo* info = *itr3;
					info->SetState(0);
					m_UserToGroup.erase(info->GetUserID());
					itr3 = infos.erase(itr3);

					//移动到未匹配列表并通知
					SCMatchResultNotify ntf;
					ntf.Result = user_id == info->GetUserID() ? 1 : 2;
					m_FreeUsers.insert(MatchInfoMap::value_type(info->GetUserID(), info));
					SendNet(info->GetUserID(), MsgID::SC_MATCH_RESULT, &ntf);
				}
				SAFE_DELETE(group);
			}
		}
	}

	void MatchModule::OnMatchConfirmRequest(NetDataItem* item)
	{
		int user_id = (int)item->key.second;
		CSMatchConfirmRequest req;
		req.Unpack(item->data, 0);
		::printf("MatchModule::OnMatchConfirmRequest user_id:%d state:%d\n", user_id, req.State);

		std::map<int, int>::iterator itr = m_UserToGroup.find(user_id);
		if (itr == m_UserToGroup.end())
		{
			::printf("Player is not in prepare group.\n");
			return;
		}
		MatchGroupMap::iterator itr2 = m_PrepareGroups.find(itr->second);
		if (itr2 == m_PrepareGroups.end())
		{
			::printf("Match group is not exists. id:%d\n", itr->second);
			return;
		}

		//逐个成员通知
		MatchGroupInfo* group = itr2->second;
		MatchInfoVector& infos = group->GetMatchInfos();
		bool all_ok = true;
		SCMatchStateNotify ntf;
		ntf.UserID = user_id;
		ntf.State = req.State;
		for (MatchInfoVector::iterator itr3 = infos.begin(); itr3 != infos.end(); ++itr3)
		{
			MatchInfo* info = *itr3;
			if (info->GetUserID() == user_id)
			{
				info->SetState(req.State);
			}
			all_ok = all_ok && (info->GetState() == 1);
			SendNet(info->GetUserID(), MsgID::SC_MATCH_STATE, &ntf);
		}

		//是否完成
		if (all_ok)
		{
			//将用户移动到匹配完成的集合，并通知
			::printf("All player of group %d is prepare ok.\n", group->GetGroupID());
			std::stringstream ss;
			SCMatchResultNotify ntf2;
			ntf2.Result = 0;
			for (MatchInfoVector::iterator itr3 = infos.begin(); itr3 != infos.end(); ++itr3)
			{
				MatchInfo* info = *itr3;
				if (itr3 != infos.begin())
				{
					ss << "_";
				}
				ss << info->GetUserID();
				m_CompleteUsers.insert(MatchInfoMap::value_type(info->GetUserID(), info));
				SendNet(info->GetUserID(), MsgID::SC_MATCH_RESULT, &ntf2);
			}
			infos.clear();
			SetBroadcastDirty();

			//移除准备集合
			itr2 = m_PrepareGroups.erase(itr2);
			SAFE_DELETE(group);			//infos不能再访问了

			//通知其它模块
			EventParam* ep = EventParam::Get(MatchEvent::EID_MATCH_COMPLETE);
			ep->s1 = ss.str();
			EventManager::GetInstance()->TriggerEvent(ep);
		}
	}

	void MatchModule::OnEventUserOnline(int id, EventParam* ep)
	{
		int user_id = ep->i1;
		::printf("MatchModule::OnEventUserOnline user_id:%d\n", user_id);
		RemovePlayer(user_id);

		//创建新的加入
		FightModule* fight_module = GetServer()->GetModule<FightModule>();
		int state = fight_module->GetPlayerFightState(user_id);
		MatchInfo* info = new MatchInfo(user_id);
		if (state == FightPlayerState::FPS_NONE || state == FightPlayerState::FPS_QUIT)
		{
			m_FreeUsers.insert(make_pair(info->GetUserID(), info));
		}
		else
		{
			m_CompleteUsers.insert(make_pair(info->GetUserID(), info));
		}
		SetBroadcastDirty();
	}

	void MatchModule::OnEventUserOutline(int id, EventParam* ep)
	{
		int user_id = ep->i1;
		::printf("MatchModule::OnEventUserOutline user_id:%d\n", user_id);
		RemovePlayer(user_id);
		SetBroadcastDirty();
	}

	void MatchModule::OnEventUserQuit(int id, EventParam* ep)
	{
		//::printf("MatchModule::OnEventUserQuit user_id:%d\n", ep->i1);
	}

	void MatchModule::OnEventFightIn(int id, EventParam* ep)
	{
		int user_id = ep->i1;
		::printf("MatchModule::FightIn user_id:%d\n", user_id);
		if (m_CompleteUsers.find(user_id) != m_CompleteUsers.end())
		{
			return;
		}
		
		MatchInfoMap::iterator itr = m_FreeUsers.find(user_id);
		if (itr != m_FreeUsers.end())
		{
			MatchInfo* info = itr->second;
			itr = m_FreeUsers.erase(itr);
			m_CompleteUsers.insert(make_pair(user_id, info));
			return;
		}
	}

	void MatchModule::OnEventFightOut(int id, EventParam* ep)
	{
		int user_id = ep->i1;
		::printf("MatchModule::FightOut user_id:%d\n", user_id);
		MatchInfoMap::iterator itr = m_CompleteUsers.find(user_id);
		if (itr == m_CompleteUsers.end())
		{
			return;
		}
		auto player = itr->second;
		m_CompleteUsers.erase(user_id);
		m_FreeUsers.insert(make_pair(user_id, player));
		m_UserToGroup.erase(player->GetUserID());
	}
}